#include "lcd_driver.h"
#include "lcd_font.h"
#include "main.h"
#include "stm32f4xx_hal.h"
#include "spi.h"
// 管理LCD重要参数
// 默认为竖屏
_lcd_dev lcddev;

// 画笔颜色,背景颜色
uint16_t POINT_COLOR = BLACK;
uint16_t BACK_COLOR = WHITE;

/*********************************************************************************
 *@name：void LCD_WR_REG（u8数据）
 *@日期：2018-08-09
 *@function：在LCD屏幕上写入8位命令
 *@parameters：data：要写入的命令值
 *@retvalue：无
 **************************************************************************************/
void LCD_WR_REG(uint8_t data)
{
	LCD_CS_CLR;
	LCD_DC_CLR;
	SPIv_WriteData(data);
	LCD_CS_SET;
}
/*********************************************************************************
 *@name：void LCD_WR_DATA（u8数据）
 *@日期：2018-08-09
 *@功能：将8位数据写入LCD屏幕
 *@parameters：data：要写入的数据值
 *@retvalue：无
 **************************************************************************************/
void LCD_WR_DATA(uint8_t data)
{
	LCD_CS_CLR;
	LCD_DC_SET;
	SPIv_WriteData(data);
	LCD_CS_SET;
}

/*********************************************************************************
 *@name：void LCD_WriteReg（u8 LCD_Reg，uint16_t LCD_RegValue）
 *@日期：2018-08-09
 *@function：将数据写入寄存器
 *@parameters：LCD_Reg：注册地址
				LCD_RegValue：要写入的数据
 *@retvalue：无
**************************************************************************************/
void LCD_WriteReg(uint8_t LCD_Reg, uint16_t LCD_RegValue)
{
	LCD_WR_REG(LCD_Reg);
	LCD_WR_DATA(LCD_RegValue);
}

/*********************************************************************************
 *@name：void LCD_WriteRAM_Prepare（void）
 *@日期：2018-08-09
 *@功能：写GRAM
 *@参数：无
 *@retvalue：无
 **************************************************************************************/
void LCD_WriteRAM_Prepare(void)
{
	LCD_WR_REG(lcddev.wramcmd);
}

/*********************************************************************************
 *@name：void Lcd_WriteData_16Bit（uint16_t数据）
 *@日期：2018-08-09
 *@function：在LCD屏幕上写一个16位命令
 *@parameters：Data：要写入的数据
 *@retvalue：无
 **************************************************************************************/
void Lcd_WriteData_16Bit(uint16_t Data)
{
	LCD_CS_CLR;
	LCD_DC_SET;
	SPIv_WriteData(Data >> 8);
	SPIv_WriteData(Data);
	LCD_CS_SET;
}

/*********************************************************************************
 *@name：void LCD_DrawPoint（uint16_t x，uint16_t y）
 *@日期：2018-08-09
 *@function：在指定位置写入像素数据
 *@parameters：x：像素的x坐标
				y：像素的y坐标
 *@retvalue：无
**************************************************************************************/
void LCD_DrawPoint(uint16_t x, uint16_t y)
{
	LCD_SetCursor(x, y); // 设置光标位置
	Lcd_WriteData_16Bit(POINT_COLOR);
}

/*********************************************************************************
 *@name：void LCD_Clear（uint16_t彩色）
 *@日期：2018-08-09
 *@功能：全屏液晶屏
 *@parameters：color：填充色
 *@retvalue：无
 **************************************************************************************/
void LCD_Clear(uint16_t Color)
{
	unsigned int i, m;
	LCD_SetWindows(0, 0, lcddev.width - 1, lcddev.height - 1);
	LCD_CS_CLR;
	LCD_DC_SET;
	for (i = 0; i < lcddev.height; i++)
	{
		for (m = 0; m < lcddev.width; m++)
		{
			SPIv_WriteData(Color >> 8);
			SPIv_WriteData(Color);
		}
	}
	LCD_CS_SET;
}
/*********************************************************************************
 *@name：void LCD_RESET（void）
 *@日期：2018-08-09
 *@功能：重置LCD屏幕
 *@参数：无
 *@retvalue：无
 **************************************************************************************/
void LCD_RESET(void)
{
	LCD_RES_CLR;
	HAL_Delay(20);
	LCD_RES_SET;
	HAL_Delay(20);
}
/*********************************************************************************
 *@name：void LCD_Init（void）
 *@日期：2018-08-09
 *@功能：初始化液晶屏
 *@参数：无
 *@retvalue：无
 **************************************************************************************/
void LCD_Init(void)
{
	LCD_RESET(); // LCD 复位
	//************* ST7789初始化**********//
	LCD_WR_REG(0x36);
	LCD_WR_DATA(0x00);

	LCD_WR_REG(0x3A);
	LCD_WR_DATA(0x05);
	//--------------------------------ST7789V Frame rate
	LCD_WR_REG(0xB2);
	LCD_WR_DATA(0x0C);
	LCD_WR_DATA(0x0C);
	LCD_WR_DATA(0x00);
	LCD_WR_DATA(0x33);
	LCD_WR_DATA(0x33);

	LCD_WR_REG(0xB7);
	LCD_WR_DATA(0x35);
	//---------------------------------ST7789V Power
	LCD_WR_REG(0xBB);
	LCD_WR_DATA(0x1F);

	LCD_WR_REG(0xC0);
	LCD_WR_DATA(0x2C);

	LCD_WR_REG(0xC2);
	LCD_WR_DATA(0x01);

	LCD_WR_REG(0xC3);
	LCD_WR_DATA(0x12);

	LCD_WR_REG(0xC4);
	LCD_WR_DATA(0x20);

	LCD_WR_REG(0xC6);
	LCD_WR_DATA(0x0F);

	LCD_WR_REG(0xD0);
	LCD_WR_DATA(0xA4);
	LCD_WR_DATA(0xA1);
	//--------------------------------ST7789V gamma
	LCD_WR_REG(0xE0);
	LCD_WR_DATA(0xD0);
	LCD_WR_DATA(0x08);
	LCD_WR_DATA(0x11);
	LCD_WR_DATA(0x09);
	LCD_WR_DATA(0x0C);
	LCD_WR_DATA(0x15);
	LCD_WR_DATA(0x39);
	LCD_WR_DATA(0x33);
	LCD_WR_DATA(0x50);
	LCD_WR_DATA(0x36);
	LCD_WR_DATA(0x13);
	LCD_WR_DATA(0x14);
	LCD_WR_DATA(0x29);
	LCD_WR_DATA(0x2D);

	LCD_WR_REG(0xE1);
	LCD_WR_DATA(0xD0);
	LCD_WR_DATA(0x08);
	LCD_WR_DATA(0x10);
	LCD_WR_DATA(0x08);
	LCD_WR_DATA(0x06);
	LCD_WR_DATA(0x06);
	LCD_WR_DATA(0x39);
	LCD_WR_DATA(0x44);
	LCD_WR_DATA(0x51);
	LCD_WR_DATA(0x0B);
	LCD_WR_DATA(0x16);
	LCD_WR_DATA(0x14);
	LCD_WR_DATA(0x2F);
	LCD_WR_DATA(0x31);

	LCD_WR_REG(0x21);

	LCD_WR_REG(0x11);
	HAL_Delay(120);

	LCD_WR_REG(0x29);
	LCD_direction(USE_HORIZONTAL); // 设置LCD显示方向
	LCD_BLK_SET;				   // 点亮背光
	LCD_Clear(WHITE);			   // 清全屏白色
}

/*********************************************************************************
 *@name：void LCD_SetWindows（uint16_t xStar，uint16_t yStar，uint16_t xEnd，uint16_t yEnd）
 *@日期：2018-08-09
 *@功能：设置LCD显示窗口
 *@parameters：xStar：LCD显示窗口的合并x坐标
yStar：LCD显示窗口的绑定y坐标
xEnd：LCD显示窗口的终止x坐标
yEnd：LCD显示窗口的结束y坐标
 *@retvalue：无
**************************************************************************************/
void LCD_SetWindows(uint16_t xStar, uint16_t yStar, uint16_t xEnd, uint16_t yEnd)
{
	LCD_WR_REG(lcddev.setxcmd);
	LCD_WR_DATA((xStar + lcddev.xoffset) >> 8);
	LCD_WR_DATA(xStar + lcddev.xoffset);
	LCD_WR_DATA((xEnd + lcddev.xoffset) >> 8);
	LCD_WR_DATA(xEnd + lcddev.xoffset);

	LCD_WR_REG(lcddev.setycmd);
	LCD_WR_DATA((yStar + lcddev.yoffset) >> 8);
	LCD_WR_DATA(yStar + lcddev.yoffset);
	LCD_WR_DATA((yEnd + lcddev.yoffset) >> 8);
	LCD_WR_DATA(yEnd + lcddev.yoffset);

	LCD_WriteRAM_Prepare(); // 开始写入GRAM
}

/*********************************************************************************
 *@name：void LCD_SetCursor（uint16_t Xpos，uint16_t Ypos）
 *@日期：2018-08-09
 *@功能：设置坐标值
 *@parameters：Xpos：像素的x坐标
Ypos：像素的y坐标
 *@retvalue：无
**************************************************************************************/
void LCD_SetCursor(uint16_t Xpos, uint16_t Ypos)
{
	LCD_SetWindows(Xpos, Ypos, Xpos, Ypos);
}

/*********************************************************************************
 *@name：void LCD_direction（u8方向）
 *@日期：2018-08-09
 *@功能：设置液晶显示屏的显示方向
 *@parameters：方向：0-0度
						  1-90度
2-180度
3-270度
 *@retvalue：无
**************************************************************************************/
void LCD_direction(uint8_t direction)
{
	lcddev.setxcmd = 0x2A;
	lcddev.setycmd = 0x2B;
	lcddev.wramcmd = 0x2C;
	switch (direction)
	{
	case 0:
		lcddev.width = LCD_W;
		lcddev.height = LCD_H;
		lcddev.xoffset = 0;
		lcddev.yoffset = 0 + LCD_Y_OFFSET;
		LCD_WriteReg(0x36, 0); // BGR==1,MY==0,MX==0,MV==0
		break;
	case 1:
		lcddev.width = LCD_H;
		lcddev.height = LCD_W;
		lcddev.xoffset = 0 + LCD_X_OFFSET;
		lcddev.yoffset = 0;
		LCD_WriteReg(0x36, (1 << 6) | (1 << 5)); // BGR==1,MY==1,MX==0,MV==1
		break;
	case 2:
		lcddev.width = LCD_W;
		lcddev.height = LCD_H;
		lcddev.xoffset = 0;
		lcddev.yoffset = 0 + LCD_Y_OFFSET;
		LCD_WriteReg(0x36, (1 << 6) | (1 << 7)); // BGR==1,MY==0,MX==0,MV==0
		break;
	case 3:
		lcddev.width = LCD_H;
		lcddev.height = LCD_W;
		lcddev.xoffset = 0 + LCD_X_OFFSET;
		lcddev.yoffset = 0;
		LCD_WriteReg(0x36, (1 << 7) | (1 << 5)); // BGR==1,MY==1,MX==0,MV==1
		break;
	default:
		break;
	}
}

/***********************************************************************
 *@name：void GUI_DrawPoint（uint16_t x，uint16_t y，uint16_t颜色）
 *@日期：2018-08-09
 *@功能：在LCD屏幕上画点
 *@parameters：x：点的x坐标
				y：点的y坐标
颜色：点的颜色值
 *@retvalue：无
************************************************************************/
void GUI_DrawPoint(uint16_t x, uint16_t y, uint16_t color)
{
	LCD_SetCursor(x, y); // 设置光标位置
	Lcd_WriteData_16Bit(color);
}

/***********************************************************************
 *@name：void LCD_Fill（uint16_t sx，uint16_t sy，uint16_t ex，uint16_t ey，uint16_t彩色）
 *@日期：2018-08-09
 *@function：填写指定区域
 *@parameters：sx：指定区域的x坐标
				sy：指定区域的y坐标
例如：指定区域的结束x坐标
ey：指定区域的结束y坐标
颜色：填充的颜色值
 *@retvalue：无
************************************************************************/
void LCD_Fill(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint16_t color)
{
	uint16_t i, j;
	uint16_t width = ex - sx + 1;	// 得到填充的宽度
	uint16_t height = ey - sy + 1;	// 高度
	LCD_SetWindows(sx, sy, ex, ey); // 设置显示窗口
	for (i = 0; i < height; i++)
	{
		for (j = 0; j < width; j++)
			Lcd_WriteData_16Bit(color); // 写入数据
	}
	LCD_SetWindows(0, 0, lcddev.width - 1, lcddev.height - 1); // 恢复窗口设置为全屏
}

/*********************************************************************************
 *@name：void Gui_Drawbmp16（uint16_t x，uint16_t y，const unsigned char *p）
 *@日期：2018-08-09
 *@功能：显示16位BMP图像
 *@parameters：x：BMP图像的x坐标
				y：BMP图像的合并y坐标
p：图像数组的起始地址
 *@retvalue：无
**************************************************************************************/
void Gui_Drawbmp16(uint16_t x, uint16_t y, uint16_t length, uint16_t width, const uint8_t *p) // 显示40*40 QQ图片
{
	int i;
	unsigned char picH, picL;
	LCD_SetWindows(x, y, x + length - 1, y + width - 1); // 窗口设置
	for (i = 0; i < length * width; i++)
	{
		picL = *(p + i * 2); // 数据低位在前
		picH = *(p + i * 2 + 1);
		Lcd_WriteData_16Bit(picH << 8 | picL);
	}
	LCD_SetWindows(0, 0, lcddev.width - 1, lcddev.height - 1); // 恢复显示窗口为全屏
}


void LCD_Color_Fill_2(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint16_t *color)
{
	uint16_t height, width;
	uint16_t i, j;
	width = ex - sx + 1;
	height = ey - sy + 1;
	for (i = 0; i < height; i++)
	{
		LCD_SetCursor(sx, sy + i);
		LCD_WriteRAM_Prepare();
		for (j = 0; j < width; j++)
			Lcd_WriteData_16Bit(color[i * height + j]);
	}
}
void LCD_Color_Fill_1(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, lv_color_t *color)
{
	uint32_t y = 0;
	uint16_t height, width;
	width = ex - sx + 1;  // 得到填充的宽度
	height = ey - sy + 1; // 高度

	LCD_SetWindows(sx, sy, ex, ey);

	for (y = 0; y < width * height; y++)
	{
		Lcd_WriteData_16Bit(color->full);
		color++;
	}

	//	LCD_SetWindows(0,0,lcddev.width-1,lcddev.height-1);//回复为全屏
}

/******************************************************************************
	  函数说明：在指定区域填充颜色
	  入口数据：xsta,ysta   起始坐标
				xend,yend   终止坐标
								color       要填充的颜色
	  返回值：  无
******************************************************************************/
void LCD_Color_Fill_DMA(uint16_t xsta, uint16_t ysta, uint16_t xend, uint16_t yend, uint16_t *color_p)
{
	uint16_t width, height;
	width = xend - xsta + 1;
	height = yend - ysta + 1;
	uint32_t size = width * height;

	LCD_SetWindows(xsta, ysta, xend, yend);

	LCD_CS_CLR;
	LCD_DC_SET;
	hspi1.Init.DataSize = SPI_DATASIZE_16BIT;
	hspi1.Instance->CR1 |= SPI_CR1_DFF;
	HAL_SPI_Transmit_DMA(&hspi1, (uint8_t *)color_p, size);
	while (__HAL_DMA_GET_COUNTER(&hdma_spi1_tx) != 0);

	hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
	hspi1.Instance->CR1 &= ~SPI_CR1_DFF;
	LCD_CS_SET;
}